module riscv_core(RST, CLK, KEY, DIPB, LEDA, LEDB, BEEP, UART_RX, UART_TX, 
    SEG_DATA, SEG_EN, DIPC, LEDC, OLED_SCL, OLED_SDA);
input RST;
input CLK;
input [3:1] KEY;
input [7:0] DIPB;
output [4:1] LEDA;
output [7:0] LEDB;
output BEEP;
input  UART_RX;
output UART_TX;
output [7:0] SEG_DATA;
output [3:0] SEG_EN;
input [7:0] DIPC;
output [7:0] LEDC;
output OLED_SCL;
output OLED_SDA;

reg [3:0] lvl0_data;
reg [3:0] lvl1_data;
reg [3:0] lvl2_data;
reg [3:0] lvl3_data;

wire [31:0] reg_wr_data;
wire [31:0] reg_rd_data1;
wire [31:0] reg_rd_data2;

reg [31:0] alu_in_a;		// alu输入A
reg [31:0] alu_in_b;		// alu输入B
wire [31:0] alu_out;		// alu输出的数据
wire [31:0] imm_out;		// 立即数生成器输出的数据

wire [2:0] ExtOP;           // 3-bit 扩展操作控制
wire       RegWr;           // 寄存器写使能
wire [2:0] Branch;          // 3-bit 分支类型
wire       MemToReg;        // 内存数据到寄存器
wire       MemWr;           // 内存写使能
wire [2:0] MemOP;           // 3-bit 内存操作类型
wire       ALUAsrc;         // ALU A输入源选择
wire [1:0] ALUBsrc;         // 2-bit ALU B输入源选择
wire [3:0] ALUop;           // 4-bit ALU操作码

wire clk;

wire zero;
wire less;
wire PCAsrc;
wire PCBsrc;
reg [31:0] pca;
reg [31:0] pcb;

reg [3:0] leda_o;
reg [7:0] ledb_o;
reg [7:0] ledc_o;
reg oled_sda_o;
reg oled_scl_o;

reg [31:0] next_inst_addr;
wire [31:0] curr_inst_addr;
wire [31:0] inst_val;

riscv_clk clk_u0(
    .RST(RST),
    .CLK_50M(CLK), 
    .clk(clk));

// PC寄存器
riscv_pc pc_reg(
	.rst(RST),
	.clk(clk),
	.pc_i(next_inst_addr),
	.pc_o(curr_inst_addr)
);

riscv_inst_rom inst_rom_unit(
    .clk(CLK),
    .inst_addr(curr_inst_addr),
    .inst_data(inst_val)
);


//控制单元
riscv_control control(
    .op(inst_val[6:2]),
    .func3(inst_val[14:12]),
    .func7(inst_val[30:30]),
    .ExtOP(ExtOP),
    .RegWr(RegWr),   
    .Branch(Branch),  
    .MemToReg(MemToReg),
    .MemWr(MemWr),   
    .MemOP(MemOP),   
    .ALUAsrc(ALUAsrc), 
    .ALUBsrc(ALUBsrc), 
    .ALUop(ALUop)
);

//寄存器集
riscv_regfile regfile(
    .rst(RST),              //复位信号，下降沿触发，低电平有效
    .clk(clk),              //时钟信号
    .we(RegWr),             //写信号, 高有效
    .rs1(inst_val[19:15]), 	//第一个source register的id
    .rs2(inst_val[24:20]), 	//第二个source register的id
    .rd(inst_val[11:7]),	//destination register的id
    .data_in(reg_wr_data),	//写入的destination register的数据
    .data_out1(reg_rd_data1), // 从第一个src register读出的数据
    .data_out2(reg_rd_data2)  // 从第二个src register读出的数据
);

//立即数生成器
riscv_imm_gen imm_gen(
	.ext_op(ExtOP),
	.inst_val(inst_val),
	.imm_out(imm_out)
);

reg [31:0] tmp;

always @(*) begin
    if (ALUBsrc==2'b01)
        tmp = imm_out;
    else
        tmp = 32'h0000_0004;

    if (ALUAsrc==1'b0)
        alu_in_a = reg_rd_data1;
    else
        alu_in_a = curr_inst_addr;

    if (ALUBsrc==2'b00)
        alu_in_b = reg_rd_data2;
    else
        alu_in_b = tmp;
end

riscv_alu alu(
    .aluop(ALUop),
    .in_a(alu_in_a),
    .in_b(alu_in_b),

    .out(alu_out),
    .zero(zero),
    .less(less)
);

branch_control branch_ctrl(
    .Branch(Branch),    // 3-bit 分支类型
    .Zero(zero),        // 零标志位
    .Less(less),        // 有符号比较结果（小于）

    .PCAsrc(PCAsrc),    // PC 的 A 输入源选择
    .PCBsrc(PCBsrc)     // PC 的 B 输入源选择
);


always @(*) begin
    if (PCAsrc == 1'b0) 
        pca = 32'h0000_0004;
    else
        pca = imm_out;
end

always @(*) begin
    if (PCBsrc == 1'b0) 
        pcb = curr_inst_addr;
    else
        pcb = reg_rd_data1;
end

always @(*) begin
    next_inst_addr = pca + pcb;
end

wire [31:0] data_ram_out;
wire dr_ce;

assign dr_ce = ((inst_val[6:2]==5'b00000 || inst_val[6:2]==5'b01000) && 
                (alu_out[31:15] == 17'h0000_1)) ? 1'b1 : 1'b0;

riscv_data_ram data_ram_unit(
    .rst(RST),
    .clk(CLK),
    .ce(dr_ce),
    .MemOp(MemOP),
    .MemWr(MemWr),
    .AddrIn(alu_out - 32'h0000_8000),
    .DataIn(reg_rd_data2),
    .DataOut(data_ram_out)
);

wire [31:0] timer_val;
riscv_timer timer_unit(
    .rst(RST),
    .clk(clk),
    .val(timer_val)
);

reg [31:0] reg_wr;
reg [31:0] extern_input;
reg uart_data_cs;
reg uart_status_cs;
reg uart_we;
reg [7:0] uart_wr_data;
wire [7:0] uart_rd_data;
wire [3:0] uart_status;

always @(*) begin
    if (MemToReg) begin
        if (alu_out[31:31] == 1)
            reg_wr = extern_input;
        else 
            reg_wr = data_ram_out;
    end
    else
        reg_wr = alu_out;
end
assign reg_wr_data = reg_wr;

always @(posedge clk) begin
    uart_data_cs <= 0;
    uart_status_cs <= 0;
    uart_we <= 0;
    uart_wr_data <= 8'h00;
    if (MemWr == 1) begin
        case (alu_out)
            32'h8000_0000: begin
                leda_o[3:0] <= reg_rd_data2[3:0];
            end
            32'h8000_0008: begin
                ledb_o[7:0] <= reg_rd_data2[7:0];
            end
            32'h8000_0010: begin    //uart
                uart_data_cs <= 1;
                uart_we <= 1;
                uart_wr_data <= reg_rd_data2[7:0];
            end
            32'h8000_001c: begin
                ledc_o[7:0] <= reg_rd_data2[7:0];
            end
            32'h8000_0024: begin
                lvl0_data <= reg_rd_data2[3:0];
            end
            32'h8000_0028: begin
                lvl1_data <= reg_rd_data2[3:0];
            end
            32'h8000_002c: begin
                lvl2_data <= reg_rd_data2[3:0];
            end
            32'h8000_0030: begin
                lvl3_data <= reg_rd_data2[3:0];
            end
            32'h8000_0040: begin
                oled_scl_o <= reg_rd_data2[0:0];
            end
            32'h8000_0044: begin
                oled_sda_o <= reg_rd_data2[0:0];
            end

        endcase
    end
    else begin
        case (alu_out)
            32'h8000_0004: begin
                extern_input <= {29'h0, KEY[3:1]};
            end
            32'h8000_000c: begin
                extern_input <= {24'h0, DIPB[7:0]};
            end
            32'h8000_0014: begin    //uart
                uart_data_cs <= 1;
                uart_we <= 0;
                extern_input <= {24'h0, uart_rd_data[7:0]};
            end
            32'h8000_0018: begin    //uart
                uart_status_cs <= 1;
                uart_we <= 0;
                extern_input <= {28'h0, uart_status[3:0]};
            end
            32'h8000_0020: begin
                extern_input <= {24'h0, DIPC[7:0]};
            end
            32'h8000_0048: begin
                extern_input <= timer_val;
            end
        endcase
    end
end

assign LEDA[4:1] = leda_o[3:0];
assign LEDB[7:0] = ledb_o[7:0];
assign LEDC[7:0] = ledc_o[7:0];
assign OLED_SCL = oled_scl_o;
assign OLED_SDA = oled_sda_o;

riscv_uart_top uart_unit(
    .CLK_50M(CLK),
    .RST_N(RST),
    .UART_RX(UART_RX),
    .UART_TX(UART_TX),
    .BEEP(BEEP),
    .core_clk(clk),
    .fifo_data_cs(uart_data_cs),            //高有效
    .fifo_status_cs(uart_status_cs),        //高有效
    .fifo_we(uart_we),                      //高有效
    .fifo_wr_data(uart_wr_data),
    .fifo_rd_data(uart_rd_data),
    .fifo_status(uart_status)
);

riscv_ssd ssd_uut(
    .CLK_50M(CLK),
    .RST_N(RST),
    .lvl0_data(lvl0_data),
    .lvl1_data(lvl1_data),
    .lvl2_data(lvl2_data),
    .lvl3_data(lvl3_data),
    .SEG_DATA(SEG_DATA),
    .SEG_EN(SEG_EN)
);

endmodule

